import pandas as pd
from os import path
import datetime

now = datetime.datetime.now()
print("Last Simtax import: " + str(now))


# parameters
first_year = 2011 #First year with parameters to import
nb_years = 6 # Number of years with parameters to import
end_year = first_year + nb_years
qc_abatment = 0.835 # Quebec's abatment
nrtc_age_rate = 0.15 # NRTC for age rate
postpone_oas_bonus = 0.072 # Anual bonus for postponing OAS pensions (simulation)
ont_socass_exempt_rate = 0.5 # For earning income only




def loadparams():
       
    
    # Loading dataset from stata
    param = dict()
    soc_ass = dict()
    soc_sol = dict()
    witb = dict()
    dict_index_fy_ey =dict(zip(range(nb_years), range(first_year, end_year)))
    dict_index_prov_fit = dict(zip(range(14), range(1, 15)))
    
    params = path.join(path.dirname(__file__), 'params')
    
    for i in range(first_year,end_year):
        param['%s'%i] = pd.read_stata(params+'/%s_parameters_nofortran.dta'%i)
        soc_ass['%s'%i] = pd.read_stata(params+'/%s_parameters_nofortran.dta'%i)
        soc_sol['%s'%i] = pd.read_stata(params+'/%s_parameters_nofortran.dta'%i)
        witb['%s'%i] = pd.read_stata(params+'/CAN/%s_WITB.dta'%i)
        
    for i in range(first_year,end_year):
        param[str('%s')%i]=param[str('%s')%i].rename(index=dict_index_prov_fit)
        
    public_pensions_parameters = pd.read_stata(params+'/public_pensions_parameters.dta')
    public_pensions_parameters = public_pensions_parameters.rename(index=dict_index_fy_ey)
    qpp_reform = pd.read_stata(params+'/QC/QPP_reform.dta')
    qpp_reform = qpp_reform.rename(index={0:2019, 1:2020, 2:2021, 3:2022, 4:2023, 5:2024, 6:2025})
    witb_qpp = pd.read_stata(params+'/QC/WITB_qpp.dta')
    fed_nrtc = pd.read_stata(params+'/CAN/fed_nrtc.dta')
    child_transf = pd.read_stata(params+'/CAN/child_transf.dta')
    child_transf = child_transf.rename(index = dict_index_fy_ey)
    gst = pd.read_stata(params+'/CAN/gst.dta')
    gst = gst.rename(index=dict_index_fy_ey)
    chcare_deduc = pd.read_stata(params+'/CAN/chcare_deduc.dta')
    chcare = pd.read_stata(params+'/QC/chcare.dta')
    qc_health_contribution = pd.read_stata(params+'/QC/QC_health_contribution_nofortran.dta')
    ramq_medic = pd.read_stata(params+'/QC/RAMQ_medic.dta')
    cap = pd.read_stata(params+'/QC/CAP.dta')
    rtc_sol = pd.read_stata(params+'/QC/rtc_sol.dta')
    rtc_sol2 = pd.read_stata(params+'/QC/rtc_sol2.dta')
    wp = pd.read_stata(params+'/QC/WP.dta')
    awp = pd.read_stata(params+'/QC/AWP.dta')
    work_deduct = pd.read_stata(params+'/QC/work_deduct.dta')
    work_deduct = work_deduct.rename(index=dict_index_fy_ey)
    nrtc_expworkert = pd.read_stata(params+'/QC/NRTC_expworkert.dta')
    nrtc_expworkert = nrtc_expworkert.rename(index = dict_index_fy_ey)
    qc_health_service_fund = pd.read_stata(params+'/QC/QC_health_service_fund.dta')
    on_health_contribution = pd.read_stata(params+'/ON/ON_health_contribution_nofortran.dta')
    gains_parameters = pd.read_stata(params+'/ON/GAINS_parameters_nofortran.dta')
    ocb_parameters = pd.read_stata(params+'/ON/OCB_parameters.dta')
    rtc_ost_parameters = pd.read_stata(params+'/ON/RTC_OST_parameters.dta')
    ontnec = pd.read_stata(params+'/ON/ONTNEC.dta')
    bcfb = pd.read_stata(params+'/BC/BCFB.dta')
    bceib = pd.read_stata(params+'/BC/BCEIB.dta')
    bcectb = pd.read_stata(params+'/BC/BCECTB.dta')
    bclicatc = pd.read_stata(params+'/BC/BCLICATC.dta')
    bcss = pd.read_stata(params+'/BC/BCSS_nofortran.dta')
    bcbts = pd.read_stata(params+'/BC/BCBTS.dta')
    bcstc = pd.read_stata(params+'/BC/BCSTC.dta')
    abfetc = pd.read_stata(params+'/AB/ABFETC.dta')
    absb = pd.read_stata(params+'/AB/ABSB.dta')
    abcb = pd.read_stata(params+'/AB/ABCB.dta')
    man55p = pd.read_stata(params+'/MAN/MAN55+_nofortran.dta')
    mancb = pd.read_stata(params+'/MAN/MANCB.dta')
    nbctb = pd.read_stata(params+'/NB/NBCTB.dta')
    nblisb = pd.read_stata(params+'/NB/NBLISB.dta')
    nlcb = pd.read_stata(params+'/NL/NLCB.dta')
    nlhstc = pd.read_stata(params+'/NL/NLHSTC.dta')
    nlsb = pd.read_stata(params+'/NL/NLSB.dta')
    nlis = pd.read_stata(params+'/NL/NLIS.dta')
    nscb = pd.read_stata(params+'/NS/NSCB.dta')
    nsaltc = pd.read_stata(params+'/NS/NSALTC.dta')
    nucb = pd.read_stata(params+'/NU/NUCB.dta')
    ntcb = pd.read_stata(params+'/NT/NTCB.dta')
    peistc = pd.read_stata(params+'/PEI/PEISTC.dta')
    sklitc = pd.read_stata(params+'/SK/SKLITC.dta')
    skes = pd.read_stata(params+'/SK/SKES.dta')
    sksip = pd.read_stata(params+'/SK/SKSIP_nofortran.dta')
    yucb = pd.read_stata(params+'/YU/YUCB.dta')
    
    list_df = [public_pensions_parameters, qpp_reform, witb_qpp, fed_nrtc, child_transf, gst, chcare_deduc,
               chcare,qc_health_contribution, ramq_medic, cap, rtc_sol, rtc_sol2, wp, awp, work_deduct,
               nrtc_expworkert, qc_health_service_fund, on_health_contribution, gains_parameters,
               ocb_parameters, rtc_ost_parameters, ontnec, bcfb, bceib, bcectb, bclicatc, bcss, bcbts,
               abfetc, absb, abcb, man55p, mancb, nbctb, nblisb, nlcb, nlhstc, nlsb, nlis, nscb,
               nsaltc, nucb, ntcb, peistc, sklitc, skes, sksip, yucb]
    
    for v in range(len(list_df)):
        list_df[v].columns = map(str.lower, list_df[v].columns)

# switch to lowercase param dict
    for year in range(first_year, end_year):
        param[str(year)].columns = map(str.lower, param[str(year)].columns)

    df_multiple = [param, soc_ass, soc_sol, witb]

    for i in range (first_year, end_year):
        for v in range(len(df_multiple)):
            list_df.append(df_multiple[v]['%s'%i])

    
    
    
    return [param,soc_ass,soc_sol,witb,public_pensions_parameters, qpp_reform, witb_qpp, fed_nrtc, child_transf, gst, chcare_deduc,
           chcare,qc_health_contribution, ramq_medic, cap, rtc_sol, rtc_sol2, wp, awp, work_deduct,
           nrtc_expworkert, qc_health_service_fund, on_health_contribution, gains_parameters,
           ocb_parameters, rtc_ost_parameters, ontnec, bcfb, bceib, bcectb, bclicatc, bcss, bcbts,
           abfetc, absb, abcb, man55p, mancb, nbctb, nblisb, nlcb, nlhstc, nlsb, nlis, nscb,
           nsaltc, nucb, ntcb, peistc, sklitc, skes, sksip, yucb]

[param,soc_ass,soc_sol,witb,public_pensions_parameters, qpp_reform, witb_qpp, fed_nrtc, child_transf, gst, chcare_deduc,
chcare,qc_health_contribution, ramq_medic, cap, rtc_sol, rtc_sol2, wp, awp, work_deduct,
nrtc_expworkert, qc_health_service_fund, on_health_contribution, gains_parameters,
ocb_parameters, rtc_ost_parameters, ontnec, bcfb, bceib, bcectb, bclicatc, bcss, bcbts,
abfetc, absb, abcb, man55p, mancb, nbctb, nblisb, nlcb, nlhstc, nlsb, nlis, nscb,
nsaltc, nucb, ntcb, peistc, sklitc, skes, sksip, yucb] = loadparams()




class Household(object):
    """Un ménage typique canadien avec toutes les caractéristiques nécessaires
    pour modéliser sa situation fiscale.

    Attributs:
        year: L'année dans laquelle le ménage est.
        prov: La province de résidence du ménage.
        ...
    """

    def __init__(
        self,
        year,
        prov,

        # Household basic characteristics
        age_1,
        age_2 = 0,
        nb_years_reportoas_1 = 0,
        nb_years_reportoas_2 = 0,
        kidages_1 = -1,
        kidages_2 = -1,
        kidages_3 = -1,
        kidages_4 = -1,
        kidages_5 = -1,
        kidages_6 = -1,
        kidages_7 = -1,
        kidages_8 = -1,
        t_immig_1 = -1,
        t_immig_2 = -1,
        ind_couple = False,
        ind_widow = False,
        immig_1 = False,
        immig_2 = False,
        invalid_1 = False,
        invalid_2 = False,

        # Household revenue sources
        inc_earning_1 = 0.0,
        inc_earning_2 = 0.0,
        inc_capital_gains_1 = 0.0,
        inc_capital_gains_2 = 0.0,
        inc_interest_1 = 0.0,
        inc_interest_2 = 0.0,
        inc_dividends_1 = 0.0,
        inc_dividends_2 = 0.0,
        inc_private_pension_1 = 0.0,
        inc_private_pension_2 = 0.0,
        inc_cpp_pension_1 = 0.0,
        inc_cpp_pension_2 = 0.0,
        inc_other_1 = 0.0,
        inc_other_2 = 0.0,
        inc_selfempl_1 = 0.0,
        inc_selfempl_2 = 0.0,
        inc_othertaxable_1 = 0.0,
        inc_othertaxable_2 = 0.0,

        # Household expenses and contributions
        rrsp_contr_1 = 0.0,
        rrsp_contr_2 = 0.0,
        daycare_exp0_7 = 0.0,
        daycare_exp8_16 = 0.0,
        daycare_exp7d = 0.0,
        med_exp_1 = 0.0,
        med_exp_2 = 0.0,

        # Other household variables
        house = False,
        north = False,
        public_medic_insurance = False,
        const = 0,
        log_ad = 0,
        penaltysa = 0.0,
        etudiant = 0,
        assets = 0.0
        ):

        # Initialize Household object
        self.year = year
        self.prov = prov
        self.age_1 = age_1
        self.age_2 = age_2
        self.nb_years_reportoas_1 = nb_years_reportoas_1
        self.nb_years_reportoas_2 = nb_years_reportoas_2
        self.kidages_1 = kidages_1
        self.kidages_2 = kidages_2
        self.kidages_3 = kidages_3
        self.kidages_4 = kidages_4
        self.kidages_5 = kidages_5
        self.kidages_6 = kidages_6
        self.kidages_7 = kidages_7
        self.kidages_8 = kidages_8
        self.t_immig_1 = t_immig_1
        self.t_immig_2 = t_immig_2
        self.ind_couple = ind_couple
        self.ind_widow = ind_widow
        self.immig_1 = immig_1
        self.immig_2 = immig_2
        self.invalid_1 = invalid_1
        self.invalid_2 = invalid_2

        # Household revenue sources
        self.inc_earning_1 = inc_earning_1
        self.inc_earning_2 = inc_earning_2
        self.inc_capital_gains_1 = inc_capital_gains_1
        self.inc_capital_gains_2 = inc_capital_gains_2
        self.inc_interest_1 = inc_interest_1
        self.inc_interest_2 = inc_interest_2
        self.inc_dividends_1 = inc_dividends_1
        self.inc_dividends_2 = inc_dividends_2
        self.inc_private_pension_1 = inc_private_pension_1
        self.inc_private_pension_2 = inc_private_pension_2
        self.inc_cpp_pension_1 = inc_cpp_pension_1
        self.inc_cpp_pension_2 = inc_cpp_pension_2
        self.inc_other_1 = inc_other_1
        self.inc_other_2 = inc_other_2
        self.inc_selfempl_1 = inc_selfempl_1
        self.inc_selfempl_2 = inc_selfempl_2
        self.inc_othertaxable_1 = inc_othertaxable_1
        self.inc_othertaxable_2 = inc_othertaxable_2

        # Household expenses and contributions
        self.rrsp_contr_1 = rrsp_contr_1
        self.rrsp_contr_2 = rrsp_contr_2
        self.daycare_exp0_7 = daycare_exp0_7
        self.daycare_exp8_16 = daycare_exp8_16
        self.daycare_exp7d = daycare_exp7d
        self.med_exp_1 = med_exp_1
        self.med_exp_2 = med_exp_2

        # Other household variables
        self.house = house
        self.north = north
        self.public_medic_insurance = public_medic_insurance
        self.const = const
        self.log_ad = log_ad
        self.penaltysa = penaltysa
        self.etudiant = etudiant
        self.assets = assets
        
        # Useful function
        self.gen_nkids_used()

    def get_tot_inc(self):
        """...
        """

        self.tot_inc_1 = (self.inc_earning_1
                          + self.inc_private_pension_1
                          + self.inc_cpp_pension_1
                          + self.inc_capital_gains_1 * 0.5
                          + self.inc_interest_1
                          + self.inc_dividends_1 * param[str(self.year)]['dividendsincrease'][self.prov]
                          + self.inc_othertaxable_1
                          + self.inc_selfempl_1)

        if self.ind_couple == True:
            self.tot_inc_2 = (self.inc_earning_2
                              + self.inc_private_pension_2
                              + self.inc_cpp_pension_2
                              + self.inc_capital_gains_2 * 0.5
                              + self.inc_interest_2
                              + self.inc_dividends_2 * param[str(self.year)]['dividendsincrease'][self.prov]
                              + self.inc_othertaxable_2
                              + self.inc_selfempl_2)
        
        self.calc_oas_inc()
        self.calc_gis_inc()
        
        # update total income with GIS and OAS
        self.tot_inc_1 += self.gis_inc_1 + self.oas_inc_1
        
        if self.ind_couple == True:
            self.tot_inc_2 += self.gis_inc_2 + self.oas_inc_2
    
    def get_oas_clawback(self):
        """...
        """
        
        oas_reduct = public_pensions_parameters.loc[self.year, 'oas_clawback']
        oas_reduct_rate = public_pensions_parameters.loc[self.year, 'oas_clawback_rate']
        
        oas_clawback = oas_reduct_rate * (self.net_inc_1 - oas_reduct)
        
        return(oas_clawback)
    
    def calc_oas_clawback(self):
        """...
        """
        oas_reduct = public_pensions_parameters.loc[self.year, 'oas_clawback']
        self.oas_clawback_1 = 0.0
        self.oas_clawback_2 = 0.0
        
        # oas clawback based on net income before adjustment
        if self.net_inc_1 > oas_reduct:
            self.oas_clawback_1 = min(self.oas_inc_1, self.get_oas_clawback())
        
        if self.ind_couple == True:
            if self.net_inc_2 > oas_reduct:
                self.oas_clawback_2 = min(self.oas_inc_2, self.get_oas_clawback())
    
    def get_qc_tot_inc(self):
        """...
        """
        
        self.qc_tot_inc_1 = self.tot_inc_1
        self.qc_tot_inc_1 = max(0.0, self.qc_tot_inc_1 - self.oas_clawback_1)

    def get_net_inc(self):
        """...
        """

        self.get_tot_inc()

        self.net_inc_1 = max(0.0,
                             self.tot_inc_1
                             - self.rrsp_contr_1)

        if self.ind_couple == True:
            self.net_inc_2 = max(0.0,
                                 self.tot_inc_2
                                 - self.rrsp_contr_2)
        
        # update net income with oas clawback
        self.calc_oas_clawback()
        
        self.net_inc_1 -= self.oas_clawback_1
        
        if self.ind_couple == True:
            self.net_inc_2 =- self.oas_clawback_2
            
    def get_qc_net_inc(self):
        """Calcule un net income spécifique au Québec.
        """
        
        self.get_qc_tot_inc()
        
        # get deduction for workers in Quebec
        earning = self.inc_earning_1 + self.inc_selfempl_1
        
        if earning > 0:
            self.qc_inc_deduc_1 = min(work_deduct.loc[self.year, 'qc_w_inc_deduc_max'],
                                      earning * work_deduct.loc[self.year, 'qc_w_inc_deduc_rate'])
            
        else:
            self.qc_inc_deduc_1 = 0.0
        
        self.qc_net_inc_1 = max(0.0,
                                self.qc_tot_inc_1
                                - self.rrsp_contr_1
                                - self.qc_inc_deduc_1)
        
    def get_taxable_inc(self):
        """...
        """
        
        self.gis_inc_1 = 0.0
        self.gis_inc_2 = 0.0

        self.qpp_contrib()
        self.get_net_inc()
        self.get_uccb()
        
        if self.prov == 5:
            self.get_qc_net_inc()
        
        if self.year >= 2019:
            self.taxable_inc_1 = max(0.0, self.net_inc_1 - self.gis_inc_1 - self.qpp_contr_supp_1)

            if self.ind_couple == True:
                self.taxable_inc_2 = max(0.0, self.net_inc_2 - self.gis_inc_2 - self.qpp_contr_supp_2)

        else:
            self.taxable_inc_1 = max(0.0, self.net_inc_1 - self.gis_inc_1)

            if self.ind_couple == True:
                self.taxable_inc_2 = max(0.0, self.net_inc_2 - self.gis_inc_2)
        
        # specific taxable income for Quebec
        if self.prov == 5:
            self.qc_taxable_inc_1 = (
                max(0.0,
                    self.qc_net_inc_1
                    - self.gis_inc_1
                    - self.uccb_1
                    + self.uccb_3
                    - self.qpp_contr_supp_1))
            
            if self.ind_couple == True:
                self.qc_taxable_inc_2 = (
                    max(0.0,
                        self.qc_net_inc_2
                        - self.gis_inc_2
                        - self.uccb_2
                        - self.qpp_contr_supp_2))
    
    def count_kidages(self, minage, maxage):
        """Compte le nombre d'enfants du ménage et crée un attribut de l'instance.
        """

        self.minage = minage
        self.maxage = maxage

        setattr(self, str(self.minage) + '_' + str(self.maxage), 0)
        nbrekids = 0
        nkids = 0

        for i in range(1,9):
            var_name = 'kidages_' + str(i)

            if getattr(self, var_name) > 0:
                nbrekids += 1

            else:
                setattr(self, 'nkids' + str(self.minage) + '_' + str(self.maxage), nkids)
                break

        if nbrekids > 0:
            for i in range(1, nbrekids + 1):
                var_name = 'kidages_' + str(i)

                if getattr(self, var_name) >= self.minage and getattr(self, var_name) <= self.maxage:
                    nkids += 1

            setattr(self, 'nkids' + str(self.minage) + '_' + str(self.maxage), nkids)
            
    def gen_nkids_used(self):
        """Création de valiables nkids utiles 
        """
        self.count_kidages(0,17)
        self.count_kidages(0,5)
        self.count_kidages(6,17)

    def qpp_contrib(self, optyear = 0):
        """Calcule les contributions au RRQ et au CPP pour le ROC.
        """

        # Quebec
        if self.prov == 5:
            self.cpp_contr_1 = (
                    public_pensions_parameters.loc[self.year, 'qpp_contr_rate']
                    * max(0.0, min(self.inc_earning_1, public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                    - public_pensions_parameters.loc[self.year, 'cpp_contr_min']))

            self.cpp_contr_2 = (
                public_pensions_parameters.loc[self.year, 'qpp_contr_rate']
                * max(0.0, min(self.inc_earning_2,public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                - public_pensions_parameters.loc[self.year, 'cpp_contr_min']))

            # QPP reform starting in 2019
            if optyear >= 2019:
                qpp_contr_s1_1 = (
                    qpp_reform.loc[self.year, 'qpp_contr_rate_s1']
                    * max(0.0, min(self.inc_earning_1, public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                        - public_pensions_parameters.loc[self.year, 'cpp_contr_min']))

                qpp_contr_s1_2 = (
                    qpp_reform.loc[self.year, 'qpp_contr_rate_s1']
                    * max(0.0, min(self.inc_earning_2, public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                        - public_pensions_parameters.loc[self.year, 'cpp_contr_min']))

                qpp_contr_s2_1 = (
                    qpp_reform.loc[self.year, 'qpp_contr_rate_s2']
                    * max(0.0, min(self.inc_earning_1, qpp_reform.loc[self.year, 'qpp_contr_max_rate_s2']
                        * public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                        - public_pensions_parameters.loc[self.year, 'cpp_contr_max']))

                qpp_contr_s2_2 = (
                    qpp_reform.loc[self.year, 'qpp_contr_rate_s2']
                    * max(0.0, min(self.inc_earning_2, qpp_reform.loc[self.year, 'qpp_contr_max_rate_s2']
                        * public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                        - public_pensions_parameters.loc[self.year, 'cpp_contr_max']))

                self.qpp_contr_supp_1 = qpp_contr_s1_1 + qpp_contr_s2_1
                self.qpp_contr_supp_2 = qpp_contr_s1_2 + qpp_contr_s2_2
                
            else:
                self.qpp_contr_supp_1 = 0.0
                self.qpp_contr_supp_2 = 0.0

        # ROC
        else:
            self.cpp_contr_1 = (
                public_pensions_parameters.loc[self.year, 'cpp_contr_rate']
                * max(0,0, min(self.inc_earning_1, public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                - public_pensions_parameters.loc[self.year, 'cpp_contr_min']))

            self.cpp_contr_2 = (
                public_pensions_parameters.loc[self.year, 'cpp_contr_rate']
                * max(0,0, min(self.inc_earning_2, public_pensions_parameters.loc[self.year, 'cpp_contr_max'])
                - public_pensions_parameters.loc[self.year, 'cpp_contr_min']))

    def ei_contrib(self):
        """Calcule les contributions à l'assurance chômage.
        """

        self.ei_contr_1 = max(0.0,
                              param[str(self.year)]['ei_contr_rate'][self.prov]
                              * min(param[str(self.year)]['ei_contr_max'][self.prov],
                                    self.inc_earning_1))

        self.ei_contr_2 = max(
            0.0, param[str(self.year)]['ei_contr_rate'][self.prov]
            * min(param[str(self.year)]['ei_contr_max'][self.prov], self.inc_earning_2))

    def rap_contrib(self):
        """Calcule les contributions à l'assurance parentale.
        """

        self.rap_contr_1 = max(
            0.0, param[str(self.year)]['rap_contr_rate'][self.prov]
            * min(param[str(self.year)]['rap_contr_max'][self.prov], self.inc_earning_1))

        self.rap_contr_2 = max(
            0.0, param[str(self.year)]['rap_contr_rate'][self.prov]
            * min(param[str(self.year)]['rap_contr_max'][self.prov], self.inc_earning_2))

    def pen_split(self, optpensplit = 0, flag_pensplit = 1):
        """Fractionne le revenu de pension
        """

        self.optpensplit = optpensplit
        self.flag_pensplit = flag_pensplit

        if optpensplit == 0:

            if ((self.inc_private_pension_1 + self.inc_private_pension_2 > 0)
                and self.ind_couple == 1
                and self.flag_pensplit == 1):

                test = 0

    def get_oas(self, for_spouse = 0):
        """Old Age Security
            Pension Sécurité de la Vieillesse
        """

        for_spouse += 1

        setattr(self, 'oas', 0.0)

        if getattr(self, 'immig_' + str(for_spouse)) == 1:

            if (getattr(self, 't_immig_' + str(for_spouse))
                - getattr(self, 'age' + str(for_spouse))
                - public_pensions_parameters.loc[self.year, 'ageoas']
                >= public_pensions_parameters.loc[self.year, 'oas_immig_mintime']):

                    self.oas = (public_pensions_parameters.loc[self.year, 'oas_full']
                                * min(40, self.t_immig - (self.age_1 - public_pensions_parameters.loc[self.year, 'ageoas'])))/40

            elif (getattr(self, 't_immig_' + str(for_spouse))
                  - (getattr(self, 'age' + str(for_spouse))
                     - public_pensions_parameters.loc[self.year, 'ageoas'])
                  < public_pensions_parameters.loc[self.year,'oas_immig_mintime']
                  and
                  getattr(self, 't_immig_' + str(for_spouse))
                  >= public_pensions_parameters.loc[self.year, 'oas_immig_mintime']):

                      self.oas = (public_pensions_parameters.loc[self.year, 'oas_full']
                                  * public_pensions_parameters.loc[self.year, 'oas_immig_mintime'])/40

            else:
                self.oas = 0

        else:
            self.oas = public_pensions_parameters.loc[self.year, 'oas_full']
        
        return(self.oas)

    def calc_oas_inc(self):
        """ Old Age Security
            Pension Sécurité de la Vieillesse
        """

        self.oas_inc_1 = 0.0
        self.oas_inc_2 = 0.0

        if self.ind_couple == 1:
            if self.age_1 >= public_pensions_parameters.loc[self.year, 'ageoas']:
                self.oas_inc_1 = self.get_oas(0)
                self.oasfull1 = public_pensions_parameters.loc[self.year, 'oas_full']

            if self.age_2 >= public_pensions_parameters.loc[self.year, 'ageoas']:
                self.oas_inc_2 = self.get_oas(1)
                self.oasfull2 = public_pensions_parameters.loc[self.year, 'oas_full']
        
        # if single
        else:
            if self.age_1 >= public_pensions_parameters.loc[self.year, 'ageoas']:
                self.oas_inc_1 = self.get_oas(0)
                self.oasfull1 = public_pensions_parameters.loc[self.year, 'oas_full']

    def get_gis_inc(self, complement=0.0):
        """ Get Guaranteed Income Supplement Income
            Supplément de revenu garanti
        """

        if self.ind_couple == 1:
            fam_work_inc = self.inc_earning_1 + self.inc_earning_2
            inc_nonearning_1 = max(0.0, self.tot_inc_1 - self.inc_earning_1)
            inc_nonearning_2 = max(0.0, self.tot_inc_2 - self.inc_earning_2)
            fam_non_work_inc = inc_nonearning_1 + inc_nonearning_2
            
            gis = max(0.0,
                      public_pensions_parameters.loc[self.year, 'gis_full_couple']
                      + (complement * public_pensions_parameters.loc[self.year, 'complement_rate'])
                      - public_pensions_parameters.loc[self.year, 'gis_reduct_rate_couple']
                      * (fam_non_work_inc
                         + max(0.0, self.inc_earning_1 - public_pensions_parameters.loc[self.year, 'gis_work_exemption'])
                         + max(0.0, self.inc_earning_2 - public_pensions_parameters.loc[self.year, 'gis_work_exemption'])))

            gis += max(0.0,
                       public_pensions_parameters.loc[self.year, 'gis_bonus_couple']
                       - public_pensions_parameters.loc[self.year, 'gis_bonus_reduct_couple']
                       * max(0.0,
                             fam_work_inc
                             + fam_non_work_inc
                             - public_pensions_parameters.loc[self.year, 'gis_bonus_exemption_coupleM']))

        else:
            fam_work_inc = self.inc_earning_1
            inc_nonearning_1 = max(0.0, self.tot_inc_1 - self.inc_earning_1)
            fam_non_work_inc = inc_nonearning_1
            
            gis = max(0.0,
                      public_pensions_parameters.loc[self.year, 'gis_full_single']
                      + (complement * public_pensions_parameters.loc[self.year, 'complement_rate'])
                      - public_pensions_parameters.loc[self.year, 'gis_reduct_rate_single']
                      * (fam_non_work_inc +
                         max(0.0,
                             self.inc_earning_1
                             - public_pensions_parameters.loc[self.year, 'gis_work_exemption'])
                         + max(0.0,
                               self.inc_earning_2
                               - public_pensions_parameters.loc[self.year, 'gis_work_exemption']))) # not supposed to be in couple
            
            gis += max(0.0,
                       public_pensions_parameters.loc[self.year, 'gis_bonus_single']
                       - public_pensions_parameters.loc[self.year, 'gis_bonus_reduct_single']
                       * max(0.0,
                             fam_work_inc
                             + fam_non_work_inc
                             - public_pensions_parameters.loc[self.year, 'gis_bonus_exemption_single']))
        
        return(gis)

    def allowcouple(self, ind_immig, t_immig):
        """For GIS Income
        """

        fam_work_inc = self.inc_earning_1 + self.inc_earning_2
        inc_nonearning_1 = max(0, self.tot_inc_1 - self.inc_earning_1)
        inc_nonearning_2 = max(0, self.tot_inc_2 - self.inc_earning_2)
        fam_non_work_inc = inc_nonearning_1 + inc_nonearning_2

        if (ind_immig < public_pensions_parameters.loc[self.year, 'oas_immig_mintime']
            and t_immig < public_pensions_parameters.loc[self.year, 'oas_immig_mintime']
            ):

            factor = t_immig/public_pensions_parameters.loc[self.year, 'oas_immig_mintime']

        else:
            factor = 1

        if ((fam_work_inc + fam_non_work_inc)
            < (public_pensions_parameters.loc[self.year, 'allowcouple_rate_test_high_inc']
               * factor * public_pensions_parameters.loc[self.year, 'allowcouple_full_oas'])
            ):

            allowcouple = max(0,
                              (public_pensions_parameters.loc[self.year,'allowcouple_full_gis'] * factor)
                              + (public_pensions_parameters.loc[self.year, 'allowcouple_full_oas'] * factor)
                              - (public_pensions_parameters.loc[self.year,'allowcouple_reduct_rate']
                                 * (fam_non_work_inc + max(0, self.inc_earning_1 - public_pensions_parameters.loc[self.year, 'allowcouple_work_exemption'])
                                    + max(0,
                                          self.inc_earning_2
                                          - public_pensions_parameters.loc['allowsurv_work_exemtion']
                                          ))))

            allowcouple += max (0,
                                (public_pensions_parameters.loc[self.year, 'allowcouple_bonus'] * factor)
                                - public_pensions_parameters.loc[self.year, 'allowcouple_bonus_reduct']
                                    * max(0,
                                          fam_work_inc
                                          + fam_non_work_inc
                                          - public_pensions_parameters.loc[self.year, 'allowcouple_bonus_exemption']
                                          ))
        else:
            allowcouple = max(0,
                              (public_pensions_parameters.loc[self.year, 'allowcouple_full_gis'] * factor)
                              - public_pensions_parameters.loc[self.year, 'allowcouple_reduct_high_inc']
                                  * max(0,
                                        fam_work_inc
                                        + fam_non_work_inc
                                        - (public_pensions_parameters.loc[self.year, 'allowcouple_rate_test_high_inc']
                                           * public_pensions_parameters.loc[self.year, 'allowcouple_full_oas']
                                           )))

    def allowsurv(self, ind_immig, t_immig):
        """For GIS Income
        """

        #fam_work_inc = self.inc_earning_1 + self.inc_earning_2
        inc_nonearning_1 = max(0, self.tot_inc_1 - self.inc_earning_1)
        #inc_nonearning_2 = max(0, self.tot_inc_2 - self.inc_earning_2)
        #fam_non_work_inc = inc_nonearning_1 + inc_nonearning_2

        if (ind_immig < public_pensions_parameters.loc[self.year, 'oas_immig_mintime']
            and t_immig < public_pensions_parameters.loc[self.year, 'oas_immig_mintime']
            ):

            factor = t_immig / public_pensions_parameters.loc[self.year, 'oas_immig_mintime']

        else:
            factor = 1

        if (self.inc_earning_1 + inc_nonearning_1
            < public_pensions_parameters.loc[self.year, 'allowsurv_rate_test_high_inc']
                * public_pensions_parameters.loc[self.year, 'allowsurv_full_oas'] * factor
            ):

            allowsurv = max(0,
                            (public_pensions_parameters.loc[self.year, 'allowsurv_full_gis'] * factor)
                            + max((public_pensions_parameters.loc[self.year, 'allowsurv_full_oas'] * factor)
                                   - public_pensions_parameters.loc[self.year, 'allowsurv_reduct_rate']
                                       * (inc_nonearning_1
                                          + max(0,
                                                self.inc_earning_1
                                                - public_pensions_parameters.loc[self.year, 'allowsurv_work_exemption']
                                                ))))

            allowsurv += max(0,
                             (public_pensions_parameters.loc[self.year, 'allowsurv_bonus' ] * factor)
                             - public_pensions_parameters.loc[self.year, 'allowsurv_bonus_reduct']
                                 * max(0,
                                       self.inc_earning_1
                                       + inc_nonearning_1
                                       - public_pensions_parameters.loc[self.year, 'allowsurv_bonus_exemption' ]
                                       ))

        else:
            allowsurv = max(0,
                            (public_pensions_parameters.loc[self.year, 'allowsurv_full_gis' ] * factor )
                            - public_pensions_parameters.loc[self.year, 'allowsurv_reduct_high_inc' ]
                                * max(0,
                                      (self.inc_earning_1
                                       + inc_nonearning_1
                                       - (public_pensions_parameters.loc[self.year]
                                           * factor * public_pensions_parameters.loc[self.year, 'allowsurv_full_oas' ]
                                          ))))

    def calc_gis_inc(self):
        """Compute GIS Income
           Need: get_gis_ins, allowcouple, alowsurv
        """

        self.gis_inc_1 = 0.0
        self.gis_inc_2 = 0.0
        
        self.allowsurv_inc = 0.0

        if self.ind_couple == 1:
            if (self.age_1 >= public_pensions_parameters.loc[self.year, 'agegis']
                and self.age_2 >= public_pensions_parameters.loc[self.year, 'agegis']
                and self.oas_inc_1 > 0
                and self.oas_inc_2 > 0
                ):

                self.gis_inc_1 = self.get_gis_inc(self.oasfull1
                                                 + self.oasfull2
                                                 - self.oas_inc_1
                                                 + self.oas_inc_2)
                self.gis_inc_2 = self.gis_inc_1

            elif (self.age_1 >= public_pensions_parameters.loc[self.year, 'agegis']
                  and self.oas_inc_1 > 0
                  ):

                self.gis_inc_1 = self.get_gis_inc(self.oasfull1
                                                 + self.oasfull2
                                                 - self.oas_inc_1
                                                 + self.oas_inc_2)

                if (self.age_2 >= public_pensions_parameters.lon[self.year, 'allow_age']
                    and self.age_2 < public_pensions_parameters.loc[self.year, 'agegis']
                    ):

                    self.gis_inc_2 = self.allowcouple(self.immig_2, self.t_immig_2)

            elif (self.age_2 >= public_pensions_parameters.loc[self.year, 'gis_age'] \
                  and self.oas_inc_2 > 0
                  ):

                self.gis_inc_2 = self.get_gis_inc(self.oasfull1
                                                 + self.oasfull2
                                                 - self.oas_inc_1
                                                 + self.oas_inc_2)

                if (self.age_1 >= public_pensions_parameters.lon[self.year, 'allow_age']
                    and self.age_1 < public_pensions_parameters.loc[self.year, 'agegis']
                    ):

                    self.gis_inc_1 = self.allowcouple(self.immig_1, self.t_immig_1)

        else:
            if (self.age_1 >= public_pensions_parameters.loc[self.year, 'agegis']
                and self.oas_inc_1 > 0
               ):

                self.gis_inc_1 = self.get_gis_inc(self.oasfull1 - self.oas_inc_1)

            if (self.age_1 >= public_pensions_parameters.loc[self.year,'allow_age']
                and self.age_1 < public_pensions_parameters.loc[self.year, 'agegis']
                and self.ind_widow == 1
                ):

                self.allowsurv_inc = self.allowsurv(self.immig_1, self.t_immig_1)
                self.gis_inc_1 += self.allowsurv_inc
    
    def get_uccb(self):
        """ Need count_kidage.
        """
        
        if self.nkids0_5 >= 1:
            if self.ind_couple:
                if self.tot_inc_1 <= self.tot_inc_2:
                    self.uccb_1 = (
                        child_transf.loc[self.year, 'uccb_amount' ] * self.nkids0_5
                         + child_transf.loc[self.year, 'uccb_6_17'] * self.nkids6_17)
                    self.uccb_2 = 0.0
                    self.uccb_3 = 0.0
                
                else:
                    self.uccb_2 = (
                        child_transf.loc[self.year, 'uccb_amount' ] * self.nkids0_5
                         + child_transf.loc[self.year, 'uccb_6_17'] * self.nkids6_17)
                    self.uccb_1 = 0.0
                    self.uccb_3 = 0.0
            
            # if single with at least one child, child claims UCCB
            else:
                self.uccb_3 = (
                    child_transf.loc[self.year, 'uccb_amount' ] * self.nkids0_5
                    + child_transf.loc[self.year, 'uccb_6_17'] * self.nkids6_17)
                self.uccb_1 = 0.0
                self.uccb_2 = 0.0
        
        # if no kids
        else:
            self.uccb_1 = 0.0
            self.uccb_2 = 0.0
            self.uccb_3 = 0.0

    def taxes(self, prov):
        """Calcule les impôts fédéraux et provinciaux dus.
        """

        self.get_taxable_inc()
        self.ei_contrib()
        self.rap_contrib()
        self.count_kidages(0,17)
        
        if prov == 5:
            taxable_inc_1 = self.qc_taxable_inc_1
            
            if self.ind_couple:
                taxable_inc_2 = self.qc_taxable_inc_2
            
        else:
            taxable_inc_1 = self.taxable_inc_1
            
            if self.ind_couple:
                taxable_inc_2 = self.taxable_inc_2

        # GROSS TAXES
        n_bracket = int(param[str(self.year)]['n_bracket'][prov])

        # if over last bracket
        if taxable_inc_1 >= param[str(self.year)]['bracket{}'.format(n_bracket)][prov]:
            bracket_1 = param[str(self.year)]['bracket{}'.format(n_bracket)][prov]
            base_1 = param[str(self.year)]['base{}'.format(n_bracket)][prov]
            rate_1 = param[str(self.year)]['rate{}'.format(n_bracket)][prov]

        else:
            for i in range(1, n_bracket + 1):
                bracket_1 = param[str(self.year)]['bracket{}'.format(i + 1)][prov]

                if taxable_inc_1 <= bracket_1:
                    bracket_1 = param[str(self.year)]['bracket{}'.format(i)][prov]
                    base_1 = param[str(self.year)]['base{}'.format(i)][prov]
                    rate_1 = param[str(self.year)]['rate{}'.format(i)][prov]

                    # leave loop once bracket is found
                    break

        inctaxes_1 = base_1 + (taxable_inc_1 - bracket_1) * rate_1

        if self.ind_couple == True:
            if taxable_inc_2 >= param[str(self.year)]['bracket{}'.format(n_bracket)][prov]:
                bracket_2 = param[str(self.year)]['bracket{}'.format(n_bracket)][prov]
                base_2 = param[str(self.year)]['base{}'.format(n_bracket)][prov]
                rate_2 = param[str(self.year)]['rate{}'.format(n_bracket)][prov]

            else:
                for i in range(1, n_bracket + 1):
                    bracket_2 = param[str(self.year)]['bracket{}'.format(i + 1)][prov]

                    if taxable_inc_2 <= bracket_2:
                        bracket_2 = param[str(self.year)]['bracket{}'.format(i)][prov]
                        base_2 = param[str(self.year)]['base{}'.format(i)][prov]
                        rate_2 = param[str(self.year)]['rate{}'.format(i)][prov]

                        break

            inctaxes_2 = base_2 + (taxable_inc_2 - bracket_2) * rate_2

        # NON-REFUNDABLE TAX CREDITS
        # age tax credit
        if self.age_1 >= param[str(self.year)]['nrtc_age'][prov]:
            nrtc_age_1 = max(0.0,
                             param[str(self.year)]['nrtc_age_max'][prov]
                             - (nrtc_age_rate
                                   * max(0.0,
                                         self.net_inc_1
                                         - param[str(self.year)]['nrtc_age_base'][prov])))

        else:
            nrtc_age_1 = 0.0

        # invalidity tax credit
        if (self.invalid_1 or self.invalid_2):
            nrtc_disabled_1 = max(0.0,
                                  param[str(self.year)]['nrtc_disabled'][prov])

        else:
            nrtc_disabled_1 = 0.0

        # single tax credit
        if self.ind_couple:
            nrtc_single_1 = 0.0

        else:
            nrtc_single_1 = max(0.0, param[str(self.year)]['nrtc_single'][prov])

        nrtc_agesingle_1 = max(0.0,
                               (nrtc_age_1 + nrtc_single_1)
                               - (nrtc_age_rate
                                     * max(0.0,
                                           self.net_inc_1
                                           - param[str(self.year)]['nrtc_age_base'][prov])))

        # nrtc transfers
        if self.ind_couple:
            if self.net_inc_1 >= self.net_inc_2:
                nrtc_transfer_fed_1 = max(0.0,
                                          min(param[str(self.year)]['nrtc_spouse_max'][13],
                                              param[str(self.year)]['nrtc_spouse'][13]
                                                  - self.net_inc_1))

                nrtc_transfer_fed_2 = 0.0

                nrtc_transfer_prov_1 = max(0.0,
                                           min(param[str(self.year)]['nrtc_spouse_max'][prov],
                                               param[str(self.year)]['nrtc_spouse'][prov]
                                                   - self.net_inc_1))

                nrtc_transfer_prov_2 = 0.0

            else:
                nrtc_transfer_fed_1 = 0.0

                nrtc_transfer_fed_2 = max(0.0,
                                          min(param[str(self.year)]['nrtc_spouse_max'][13],
                                              param[str(self.year)]['nrtc_spouse'][13]
                                                  - self.net_inc_1))

                nrtc_transfer_prov_1 = 0.0

                nrtc_transfer_prov_2 = max(0.0,
                                           min(param[str(self.year)]['nrtc_spouse_max'][prov],
                                               param[str(self.year)]['nrtc_spouse'][prov]
                                                   - self.net_inc_1))

        # if single
        else:
            # if has kids
            if self.nkids0_17 > 0:
                nrtc_transfer_fed_1 = max(0.0,
                                          min(param[str(self.year)]['nrtc_depend_max'][13],
                                              param[str(self.year)]['nrtc_depend'][13]
                                              - self.uccb_3))

                nrtc_transfer_prov_1 = max(0.0,
                                           min(param[str(self.year)]['nrtc_depend_max'][prov],
                                               param[str(self.year)]['nrtc_depend'][prov]
                                               - self.uccb_3))

            else:
                nrtc_transfer_fed_1 = 0.0
                nrtc_transfer_prov_1 = 0.0
        
        # Quebec taxes don't take into account cpp, ei and rap
        if prov == 5:
            cpp_contr_1 = 0.0
            ei_contr_1 = 0.0
            rap_contr_1 = 0.0
            
        else:
            cpp_contr_1 = self.cpp_contr_1
            ei_contr_1 = self.ei_contr_1
            rap_contr_1 = self.rap_contr_1
        
        nrtc_1 = (param[str(self.year)]['nrtc_basic'][prov]
                  + nrtc_transfer_fed_1
                  + cpp_contr_1
                  + ei_contr_1
                  + rap_contr_1
                  + nrtc_agesingle_1
                  + param[str(self.year)]['nrtc_age_bonus'][prov]
                  + nrtc_disabled_1
                  + min(param[str(self.year)]['nrtc_pension_max'][prov],
                        self.inc_private_pension_1)
                  + min(param[str(self.year)]['nrtc_empl'][prov],
                        self.inc_earning_1)
                  + param[str(self.year)]['nrtc_child'][prov] * self.nkids0_17)

        nrtc_transfer_qc_1 = (inctaxes_1
                              - nrtc_1 * param[str(self.year)]['nrtc_rate'][prov])
        
        inctaxes_1 = max(0.0, nrtc_transfer_qc_1)
        temp = inctaxes_1
        
        if (prov == 5 and self.age_1 >= 65 and self.year >= 2012):
            nrtc_transfer_qc_1 = (
                min(inctaxes_1
                    - min(max(0.0, self.inc_earning_1 - nrtc_expworkert.loc[self.year]['expworker_start']),
                          nrtc_expworkert.loc[self.year]['expworker_amount'])
                    * nrtc_expworkert.loc[self.year]['expworker_rate'],
                    max(0.0,
                        inctaxes_1
                        - (param[str(self.year)]['nrtc_basic'][prov]
                           + nrtc_age_1)
                        * param[str(self.year)]['nrtc_rate'][prov])))

            nrtc_transfer_nonqc_1 = 0.0

        if (prov == 5 and self.age_1 == 64 and self.year >= 2016):
            nrtc_transfer_qc_1 = (
                min(inctaxes_1
                    - min(max(0.0, self.inc_earning_1 - nrtc_expworkert.loc[self.year]['expworker_start']),
                          nrtc_expworkert.loc[self.year]['expworker_amount_64'])
                    * nrtc_expworkert.loc[self.year]['expworker_rate'],
                    max(0.0,
                        inctaxes_1
                        - (param[str(self.year)]['nrtc_basic'][prov]
                           + nrtc_age_1)
                        * param[str(self.year)]['nrtc_rate'][prov])))

            nrtc_transfer_nonqc_1 = 0.0

        if prov != 5:
            nrtc_transfer_qc_1 = 0.0
            nrtc_transfer_nonqc_1 = 0.0

            if inctaxes_1 == 0.0:
                nrtc_transfer_nonqc_1 = (
                    nrtc_age_1
                    + param[str(self.year)]['nrtc_child'][prov]
                        * self.nkids0_17
                    + min(self.inc_private_pension_1,
                          param[str(self.year)]['nrtc_pension_max'][prov]))

            if (taxable_inc_1 < param[str(self.year)]['bracket2'][prov]):
                nrtc_transfer_nonqc_1 = (
                    max(0.0,
                        nrtc_transfer_nonqc_1
                        - max(0.0,
                              taxable_inc_1
                              - param[str(self.year)]['nrtc_basic'][prov]
                              + self.cpp_contr_1
                              + self.ei_contr_1
                              + self.rap_contr_1
                              + min(param[str(self.year)]['nrtc_empl'][prov],
                                    self.inc_earning_1))))

            else:
                nrtc_transfer_nonqc_1 = (
                    max(0.0,
                        nrtc_transfer_nonqc_1
                        - max(0.0,
                              temp/param[str(self.year)]['rate1'][prov]
                              - param[str(self.year)]['nrtc_basic'][prov]
                              + self.cpp_contr_1
                              + self.ei_contr_1
                              + self.rap_contr_1
                              + min(param[str(self.year)]['nrtc_empl'][prov],
                                    self.inc_earning_1))))

        # if Quebec
        else:
            nrtc_transfer_nonqc_1 = 0.0

        # can only be transfered if negative
        if nrtc_transfer_qc_1 > 0.0:
            nrtc_transfer_qc_1 = 0.0

        # surtaxes
        n_surtaxes = param[str(self.year)]['n_surtaxes'][prov]

        if n_surtaxes > 0:
            prov_surtax = 0.0

            for i in range(1, n_surtaxes + 1):
                prov_surtax += max(0.0,
                                   inctaxes_1
                                   - param[str(self.year)]['surtax{}'.format(i)][prov]
                                   * param[str(self.year)]['surtaxrate{}'.format(i)][prov])

            inctaxes_1 += prov_surtax

        # if single
        else:
            return(inctaxes_1)

    def inctaxes(self):
        """Une fonction wrapper qui appelle la fonction taxes 2 fois
        (provincial et fédéral)
        """

        if self.ind_couple:
            hh_fed_taxes = self.taxes(14)
            fed_inctaxes_1 = hh_fed_taxes[0]
            fed_inctaxes_2 = hh_fed_taxes[1]

            # factor in Quebec abatment
            self.fed_inctaxes_1 = fed_inctaxes_1 * qc_abatment
            self.fed_inctaxes_2 = fed_inctaxes_2 * qc_abatment

            hh_prov_taxes = self.taxes(self.prov)
            self.prov_inctaxes_1 = hh_prov_taxes[0]
            self.prov_inctaxes_2 = hh_prov_taxes[1]

            # total taxes
            self.taxes_1 = self.fed_inctaxes_1 + self.prov_inctaxes_1
            self.taxes_2 = self.fed_inctaxes_2 + self.prov_inctaxes_2

        # if single
        else:
            fed_inctaxes_1 = self.taxes(14)
            
            # factor in Quebec abatment
            self.fed_inctaxes_1 = fed_inctaxes_1 * qc_abatment

            self.prov_inctaxes_1 = self.taxes(self.prov)

            #total taxes
            self.taxes_1 = self.fed_inctaxes_1 + self.prov_inctaxes_1
        
    def prov_household_taxcredits (self):
        """...
        """
        taxred_clawbackstart = param[str(self.year)]['taxred_clawbackstart'][self.prov]
        
        if (param[str(self.year)]['taxred_defn'][self.prov] >0):
            if (param[str(self.year)]['taxred_defn'][self.prov] ==1):
                if(self.ind_couple==1):
                    if(self.prov ==1):
                        taxred_clawbackstart = param[str(self.year)]['taxred_clawbackstart_fam'][self.prov]
                
                    gainfromtaxred_1 = max(0,self.prov_inctaxes_1 - max(0, param[str(self.year)]['taxred'][self.prov] +\
                                       param[str(self.year)]['taxred_spouse'][self.prov] - max(0, self.net_inc_1 + self.net_inc_2 -\
                                       taxred_clawbackstart) * param[str(self.year)]['taxred_clawbackstartrate'][self.prov] ))
                    
                    gainfromtaxred_2 = max(0,self.prov_inctaxes_2 - max(0, param[str(self.year)]['taxred'][self.prov] +\
                                       param[str(self.year)]['taxred_spouse'][self.prov] - max(0, self.net_inc_1 + self.net_inc_2 -\
                                       taxred_clawbackstart) * param[str(self.year)]['taxred_clawbackstartrate'][self.prov] ))
                    
                    gainfromtaxred_1 = self.prov_inctaxes_1 - gainfromtaxred_1
                    gainfromtaxred_2 = self.prov_inctaxes_2 - gainfromtaxred_2
                    
                    if(gainfromtaxred_1 >gainfromtaxred_2):
                        self.prov_inctaxes_1 = max(0,self.prov_inctaxes_1 - max(0, param[str(self.year)]['taxred'][self.prov] +\
                                       param[str(self.year)]['taxred_spouse'][self.prov] - max(0, self.net_inc_1 + self.net_inc_2 -\
                                       taxred_clawbackstart) * param[str(self.year)]['taxred_clawbackstartrate'][self.prov] ))
                    
                    else:
                        self.prov_inctaxes_2 = max(0,self.prov_inctaxes_2 - max(0, param[str(self.year)]['taxred'][self.prov] +\
                                       param[str(self.year)]['taxred_spouse'][self.prov] - max(0, self.net_inc_1 + self.net_inc_2 -\
                                       taxred_clawbackstart) * param[str(self.year)]['taxred_clawbackstartrate'][self.prov] ))
                        
                else:
                    
                    self.prov_inctaxes_1 = max(0, self.prov_inctaxes_1 - max(0, param[str(self.year)]['taxred'][self.prov] -\
                                           max(0, self.net_inc_1- taxred_clawbackstart)* \
                                           param[str(self.year)]['taxred_clawbackstartrate'][self.prov]))
                
            elif(param[str(self.year)]['taxred_defn'][self.prov] ==2):
                
                self.prov_inctaxes_1 = max(0,self.prov_inctaxes_1 - max(0, param[str(self.year)]['taxred'][self.prov] - \
                                       max(0, self.net_inc_1 - taxred_clawbackstart) * param[str(self.year)]['taxred_clawbackstartrate'][self.prov] ))
        
                self.prov_inctaxes_2 = max(0,self.prov_inctaxes_2 - max(0, param[str(self.year)]['taxred'][self.prov] - \
                                       max(0, self.net_inc_2 - taxred_clawbackstart) * param[str(self.year)]['taxred_clawbackstartrate'][self.prov] ))
                
            elif(param[str(self.year)]['taxred_defn'][self.prov] ==3):
                
                if(self.ind_couple ==1):
                    
                    if(self.net_inc_1 > self.net_inc_2):
                        
                        self.prov_inctaxes_1 = max(0,self.prov_inctaxes_1 - max(0,(param[str(self.year)]['taxred'][self.prov] +\
                                               param[str(self.year)]['taxred_ch_handdep'][self.prov] * \
                                               max(0,self.nkids0_17))*2-self.prov_inctaxes_1)) 
                        self.prov_inctaxes_2 = max(0, self.prov_inctaxes_2 - max(0, param[str(self.year)]['taxred'][self.prov] *\
                                               2 - self.prov_inctaxes_2))
                
                    else:
                        self.prov_inctaxes_1 = max(0, self.prov_inctaxes_1 - max(0, param[str(self.year)]['taxred'][self.prov] *\
                                               2 - self.prov_inctaxes_1))
                        self.prov_inctaxes_2 = max(0,self.prov_inctaxes_2 - max(0,(param[str(self.year)]['taxred'][self.prov] +\
                                               param[str(self.year)]['taxred_ch_handdep'][self.prov] * \
                                               max(0,self.nkids0_17))*2-self.prov_inctaxes_2)) 
                else:
                    
                    self.prov_inctaxes_1 = max(0,self.prov_inctaxes_1 - max(0,(param[str(self.year)]['taxred'][self.prov] +\
                                               param[str(self.year)]['taxred_ch_handdep'][self.prov] * \
                                               max(0,self.nkids0_17))*2-self.prov_inctaxes_1)) 
                    
    def dividends_taxcredit(self):
        """Compute dividends tax credit provincial and federal
        """
        
        if(self.ind_couple == 1):
            
            self.prov_inctaxes_1 = max(0,self.prov_inctaxes_1 - self.inc_dividends_1 * \
                                       param[str(self.year)]['dividendscreditrate'][self.prov])
            self.prov_inctaxes_2 = max(0,self.prov_inctaxes_2 - self.inc_dividends_2 * \
                                       param[str(self.year)]['dividendscreditrate'][self.prov])
            
            self.fed_inctaxes_1 = max(0, self.fed_inctaxes_1 - self.inc_dividends_1 * \
                                      param[str(self.year)]['dividendscreditrate'][14])
            self.fed_inctaxes_2 = max(0, self.fed_inctaxes_2 - self.inc_dividends_2 * \
                                      param[str(self.year)]['dividendscreditrate'][14])
            
        else:
            
            self.prov_inctaxes_1 = max(0,self.prov_inctaxes_1 - self.inc_dividends_1 * \
                                       param[str(self.year)]['dividendscreditrate'][self.prov])
            
            self.fed_inctaxes_1 = max(0, self.fed_inctaxes_1 - self.inc_dividends_1 * \
                                      param[str(self.year)]['dividendscreditrate'][14])
            
    def gstc(self):
        """Compute general sales tax credit
        """
        
        fam_net_inc = self.net_inc_1 +self.net_inc_2 - self.uccb
        
        if(self.ind_couple == 1):
          
            self.gstc = max(0, gst.loc[self.year, 'rtc_gst_max'] + gst.loc[self.year, 'rtc_gst_max_partner'] +\
                        max(0, self.nkids0_17 * gst.loc[self.year, 'rtc_gst_max_child' ]) - \
                        max(0, gst.loc[self.year,'rtc_gst_clawrate'] * (fam_net_inc - gst.loc[self.year, 'rtc_gst_red' ]))) 
            
        else:
            if(self.nkids0_17 > 0):
                
                self.gstc = max(0, gst.loc[self.year, 'rtc_gst_max'] + gst.loc[self.year, 'rtc_gst_max_partner'] +\
                            (self.nkids0_17 -1) * gst.loc[self.year, 'rtc_gst_max_child' ] + \
                            gst.loc[self.year, 'rtc_gst_ind_bonus'] - \
                            max(0, gst.loc[self.year,'rtc_gst_clawrate'] * (fam_net_inc - gst.loc[self.year, 'rtc_gst_red' ])))
            
            else:
                
                self.gstc = max(0, gst.loc[self.year, 'rtc_gst_max'] + (min( gst.loc[self.year, 'rtc_gst_ind_bonus'],max(0, fam_net_inc -\
                            gst.loc[self.year, 'rtc_gst_ind_bonusstart']) * gst.loc[self.year, 'rtc_gst_ind_bonusrate'])) - \
                            max(0, gst.loc[self.year,'rtc_gst_clawrate'] * (fam_net_inc - gst.loc[self.year, 'rtc_gst_red' ])))


    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    